<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 1. 两个问题 修改obj.ok = false -> 然后修改obj.text -> 不去执行副作用函数
        // 

        /*   
            第一次进入的时候
             ok访问变量时-> effect（） -> cleanUp执行 -> 副作用函数执行 -> 执行get函数 
             -> track函数 effectFn添加给activeAffect变量(effectFn 里面执行了 cleanUp函数和fn()) 
             -> 给activeAffect函数的deps变量添加deps集合，就是跟当前副作用函数有关的集合
             
             text会再次执行一次 -> 
        */
        /*   修改值obj.ok = false 的时候：
              -> set -> trigger -> effect()执行 -> effectFn自行 
              -> cleanUp执行 清除副作用函数 -> 副作用函数执行 
              -> 打印“执行了副作用函数” 
              -> 还会读取一下ok

             修改obj.text = '44'
             直接 set -> trigger -> 执行副作用函数 return
              
        */
        // 2. 解决set解构的无限递归的问题 除掉了副作用函数集合 添加 又多了副作用函数集合
        let data = {
            text: 'xiaobai',
            ok: true
        }
        let activeAffect
        let bucket = new WeakMap()
        let obj = new Proxy(data, {
            get(target, key) {
                debugger
                track(target, key)
                console.log('读取了', key);
                return target[key]
            },
            set(target, key, newVal) {
                debugger
                target[key] = newVal
                trigger(target, key)
                return true
            }
        })
        function track(target, key) {
            debugger
            let depMap = bucket.get(target)
            if (!depMap) {
                bucket.set(target, (depMap = new Map()))
            }
            let deps = depMap.get(key)
            if (!deps) {
                depMap.set(key, (deps = new Set()))
            }
            deps.add(activeAffect)
            // 在get读取变量的时候就要这么去操作
            // 新增 把deps副作用集合添加到activeAffect变量中去
            activeAffect.deps.push(deps)
        }
        function trigger(target, key) {
            debugger
            let depMap = bucket.get(target)
            if (!depMap) return
            let effects = depMap.get(key)
            if (!effects) return
            // （避免无限循环）创建一个新的set 数据是effects 然后遍历执行它
            // 如果直接effects 然后遍历执行
            let newSet = new Set(effects)
            newSet.forEach(effect => effect())
        }

        function effect(fn) {
            debugger
            const effectFn = () => {
                // 执行前 先清除当前的副作用函数 然后
                cleanUp(effectFn)
                activeAffect = effectFn
                fn()
            }
            effectFn.deps = []
            effectFn()
        }
        function cleanUp(effectFn) {
            debugger
            for (let i = 0; i < effectFn.deps.length; i++) {
                let deps = effectFn.deps[i]
                // deps是一个集合 deps.delete是从集合中删除 effectFn函数
                // 而for循环 则是从所有的集合中删除effectFn函数
                deps.delete(effectFn)
            }
            effectFn.deps.length = 0
        }
        effect(() => {
            debugger
            console.log('执行了副作用函数');
            document.querySelector('body').innerHTML = obj.ok ? obj.text : 'not'
        })

    </script>
</body>

</html>